import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ThreadDemo {
    protected static int task(String taskName) {
        // 获取 1000 内的随机数 作为 sleep 的毫秒数
        Random intRand = new Random();
        int sleepAsTaskTime = intRand.nextInt(1001);
        DateTimeDemo.logTs(taskName+", sleep "+sleepAsTaskTime);
        try {
            // 使用 sleep 模拟任务执行
            Thread.sleep(sleepAsTaskTime);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        DateTimeDemo.logTs("task:"+taskName+", done");

        return sleepAsTaskTime;
    }

    protected static void multiThreadDemo() {

        // 4个任务ABCD
        // C依赖AB完成
        // D和ABC无关，期望尽量快执行完成所有任务

        // https://www.runoob.com/java/java-multithreading.html
//        Java 提供了三种创建线程的方法：
//
//        通过实现 Runnable 接口；
//        通过继承 Thread 类本身；
//        通过 Callable 和 Future 创建线程。

        // 方法 1：实现 Runnable 接口
        Thread threadA = new Thread(()->{
            ThreadDemo.task("TaskA by lambda");
        });

        // 方法 2：继承 Thread 类本身
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                ThreadDemo.task("TaskB override Thread.run");
            }
        });


        Thread threadC = new Thread(new Runnable() {
            @Override
            public void run() {
                ThreadDemo.task("TaskC override Thread.run");
            }
        });

        // 方法 3：Callable 和 Future 创建线程。
        class CallableThreadTest implements Callable<Integer> {
            @Override
            public Integer call() throws Exception {
                int taskTime = ThreadDemo.task("TaskD override Callable.call");
                return taskTime;
            }
        }
        CallableThreadTest ctt = new CallableThreadTest();
        FutureTask<Integer> ft = new FutureTask<Integer>(ctt);

        Thread threadD = new Thread(ft,"有返回值的线程threadD");

        threadA.start();
        threadB.start();
        threadD.start();

        try {
            threadA.join();
            threadB.join();

            threadC.start(); // C依赖AB完成

            threadC.join();
            threadD.join();

            System.out.println("子线程的返回值："+ft.get());

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    protected static ReentrantLock lock4A = new ReentrantLock(); // 独占锁，不能再多个线程共享
    protected static volatile boolean tABeginRun = false;
    protected static volatile boolean tBBeginRun = false;
    protected static ReentrantLock lock4B = new ReentrantLock();// 独占锁，不能再多个线程共享
    //protected static ReentrantReadWriteLock lock4A = new ReentrantReadWriteLock();
    //protected static ReentrantReadWriteLock lock4B = new ReentrantReadWriteLock();
    protected static void concurrencyByLock() {
        // 4个任务ABCD
        // C依赖AB完成
        // D和ABC无关，期望尽量快执行完成所有任务


        // https://www.jianshu.com/p/ae25eb3cfb5d
        // https://zhuanlan.zhihu.com/p/420560153
        // https://blog.csdn.net/zhengzhaoyang122/article/details/110847701

        tABeginRun = false;
        Thread threadA = new Thread(()->{
            DateTimeDemo.logTs("threadA run");
            lock4A.lock(); // lock 和 unlock 必须在同一个线程，十分蛋疼
            tABeginRun = true; // 写 所有线程可见的一个 变量，让自旋的C线程跳出自旋，开始lock
            ThreadDemo.task("TaskA");
            lock4A.unlock();
        });
        //threadA.start();

        tBBeginRun = false;
        Thread threadB = new Thread(()->{
            DateTimeDemo.logTs("threadB run");
            lock4B.lock();// lock 和 unlock 必须在同一个线程，十分蛋疼
            tBBeginRun = true;// 写 所有线程可见的一个 变量，让自旋的C线程跳出自旋，开始lock
            ThreadDemo.task("TaskB");
            lock4B.unlock();
        });
        //threadB.start();

        Thread threadD = new Thread(()->{
            DateTimeDemo.logTs("threadD run");
            ThreadDemo.task("TaskD");
        });
        //threadD.start();

        Thread threadC = new Thread(()->{
            DateTimeDemo.logTs("threadC run");

            // 为了避免 C 先于AB lock，自旋读取 所有线程可见的一个 变量，待AB写入后，跳出自旋，开始lock
            long spinCout = 0;
            while ( !tABeginRun || !tBBeginRun) {
                // 自旋
                ++spinCout;
            }
            DateTimeDemo.logTs("threadC spinCout="+spinCout);

            lock4A.lock();
            lock4B.lock();
            ThreadDemo.task("TaskC");  // C依赖AB完成
            lock4B.unlock();
            lock4A.unlock();
        });
        threadC.start();

        //故意将 ABD安排在C后面启动
        threadA.start();
        threadB.start();
        threadD.start();

        try {
            threadC.join();
            threadD.join(); // 等待所有线程结束
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    protected static void concurrencyBySemaphore() {
        // https://blog.csdn.net/weixin_45787528/article/details/123818979

        // 4个任务ABCD
        // C依赖AB完成
        // D和ABC无关，期望尽量快执行完成所有任务

        Semaphore semaphore = new Semaphore(2);

        Thread threadA = new Thread(()->{
            ThreadDemo.task("Semaphore TaskA");
            semaphore.release();
        });

        Thread threadB = new Thread(()->{
            ThreadDemo.task("Semaphore TaskB");
            semaphore.release();
        });

        Thread threadC = new Thread(()->{
            try {
                ThreadDemo.task("Semaphore TaskC begin, semaphore.availablePermits = "+ semaphore.availablePermits());
                semaphore.acquire();
                semaphore.acquire();
                ThreadDemo.task("Semaphore TaskC"); // C依赖AB完成
            }catch(InterruptedException e){
                e.printStackTrace();
            }finally{
                semaphore.release();
                semaphore.release();
            }

        });

        Thread threadD = new Thread(()->{
            ThreadDemo.task("Semaphore TaskD");
        });

        try {
            semaphore.acquire();
            semaphore.acquire();

            threadC.start();

            //故意将 ABD安排在C后面启动
            threadA.start();
            threadB.start();
            threadD.start();
        } catch(InterruptedException e){
            e.printStackTrace();
        }
    }
    protected static void demoLogic() {
        // 使用Thread.join 控制 并发线程协同
        DateTimeDemo.logTs("multiThreadDemo");
        multiThreadDemo();

        // 使用锁 控制 并发线程协同
        DateTimeDemo.logTs("concurrencyByLock");
        concurrencyByLock();

        // 使用信号量 控制 并发线程协同
        DateTimeDemo.logTs("concurrencyBySemaphore");
        concurrencyBySemaphore();
    }
}
